/*
 * Summary
 * The controller handles the Bluetooth connection, and the actions performed on it.
 * Implemented as a singleton
 * Has the interface IBluetoothController (work in progress)
 * 
 * 
 */
package com.example.bluetoothexample.BluetoothLayer;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;

public class Controller implements IBluetoothController{
	/*
	 * For debugging purposes
	 */
    private static final String TAG = "Controller";
    private static final boolean D = true;
    /*
     * Singleton instance
     */
    private static Controller instance = null;
    /*
     * holds the status of the doors and lights received from the serverstream, these are static so they can be reached
     * from different classes.
     */
    private boolean lockedStatus;
    private boolean lightStatus;
    private boolean oilStatus;

	/*
     * SERVICE_UUID The Service UniversallyUniqueIdentifier, this has to be the same on the client and server
     * DEVICE_ID The servers bluetooth MAC address ( "00:15:83:50:AD:6E" is Ronni - "1C:4B:D6:17:88:EC" is Mads )
     */
	private static final UUID SERVICE_UUID = UUID.fromString("83a84742-6070-46b0-9ab7-d27531da2197");
	private static final String DEVICE_ID = "1C:4B:D6:17:88:EC"; //<-- 
	/*
	 * Bluetooth specific objects
	 * BluetoothAdapter gets the Local adapter
	 * Socket and Device is of course a Bluetooth socket/device
	 */
	private static BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
	private static BluetoothSocket bluetoothSocket;
	private BluetoothDevice bluetoothDevice;
	private final Handler handler; 
	/*
	 * Used to hold the RecieveData object, this is used for the preliminary check, if the lights/doors are locked/on
	 */
	private RecieveData reciever; 
	private static Context mainActivity;
	

	/*
	 * When the Controller is instantiated, it starts the AsyncTask thread, that connects the bluetooth devices
	 */
	private Controller(Handler handler)
	{
		this.handler = handler;
		connectBluetooth();
		
	}
	/*
	 * The singleton instance
	 */
	public static Controller getInstance(Handler handler)
	{
		if(instance ==null)
		{
			instance = new Controller(handler);
			Log.d(TAG,"new controller object instantiated");
		}
		return instance;
	}
	
	public void connectBluetooth()
	{
		new ConnectBluetooth().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"Connect");
	}
	public RecieveData getReciever() {
		return reciever;
	}
	/*
	 * Starts the AsyncTask thread that connects the bluetooth devices
	 * bluetooth.getRemoteDevice(DEVICE_ID), this gets the device, the local device is paired with(the server)
	 * bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(SERVICE_UUID); creates a socket to the server
	 * bluetoothSocket.connect(); connects the socket between client and server
	 * 
	 * When connected,Starts listening to the servers messages
	 * RecieveData.getInstance(bluetoothSocket); 
	 * reciever.startThread();
	 * 
	 * onPostExecute()
	 * When connection has been established, the client calls to see if the doors are locked/lights are on
	 * by sending a message to the server
	 */
	private class ConnectBluetooth extends AsyncTask<String, BluetoothSocket, Boolean> {
	     protected Boolean doInBackground(String... urls) {
	    	
	    	
	    	if(checkBluetoothSupport())
	    	{
	    		
	    		
	    			
	    				bluetoothDevice = bluetoothAdapter.getRemoteDevice(DEVICE_ID);
	    				Log.d(TAG,"Name: " + bluetoothDevice.getName());
	    				
	    				try {
	    					bluetoothSocket = null;
	    					
	    					bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(SERVICE_UUID);
	    					//Method m = bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
	    					//bluetoothSocket = (BluetoothSocket) m.invoke(bluetoothDevice, 1);
	    					
	    					Log.d(TAG,"BluetoothSocket in connectbluetooththread: " + bluetoothSocket.getRemoteDevice().getName());
	    					bluetoothAdapter.cancelDiscovery();
	    					bluetoothSocket.connect();
	    					
	    					reciever = RecieveData.getInstance(handler);
	    					reciever.startThread();
	    					
	    					publishProgress(bluetoothSocket);
	    				} catch (IOException e) {
	    					// TODO Auto-generated catch block
	    					Log.e(TAG, "ConnectBluetoothThreadIO" + e.getMessage());
	    					e.printStackTrace();
	    					
	    				}catch(Exception ex)
	    				{
	    					Log.e(TAG, "ConnectBluetoothThreadEX" + ex.getMessage());
	    					ex.printStackTrace();
	    				}
	    		}
			
			return true;
	    	 
	     }

	     protected void onProgressUpdate(BluetoothSocket... progress) {
	    	 Log.d(TAG,"onprogressupdate: " + progress[0].isConnected());
	     }

	     protected void onPostExecute(Boolean result) {
	    	 sendData(ServiceCommands.IS_LOCKED);
	    	 sendData(ServiceCommands.IS_LIGHTS_ON);
		        
	     }
	 }
	
	public boolean checkBluetoothSupport()
	{
    	boolean support = true;
    	
		if(bluetoothAdapter==null)
    	{
			support = false;
    		Log.d(TAG, "Bluetooth Not Supported, no Adapter");
    	}else{
    		Log.d(TAG, "Bluetooth IS Supported");
    		if(!bluetoothAdapter.isEnabled())
    		{
    			support = false;
    			Log.d(TAG, "Bluetooth IS Turned OFF");
    		}else{
    			Log.d(TAG, "Bluetooth IS Turned ON");
    		}
    	}
		return support;
	}
	/*
	 * Sends a string of data to the server
	 * @param message to server, type of String
	 */
	public void sendData(String message)
	{
		
    	if(checkBluetoothSupport())
    	{
    		new SendData(message,handler);
    		
    	}
		
	}
	/*
	 * Gets the connection status
	 * @return boolean
	 */
	public boolean getConnectionStatus()
	{
		return bluetoothSocket.isConnected();
	}
	/*
	 * Getts and setters for Bluetooth stuff
	 */
	public BluetoothAdapter getBluetoothAdapter() {
		return bluetoothAdapter;
	}
	public static BluetoothSocket getBluetoothSocket() {
		return Controller.bluetoothSocket;
	}
	public BluetoothDevice getBluetoothDevice() {
		return bluetoothDevice;
	}
	/*
	 * getting/setting variables in this class
	 */
	public boolean isLockedStatus() {
		return lockedStatus;
	}
	public void setLockedStatus(boolean lockedStatus) {
		this.lockedStatus = lockedStatus;
	}
	public boolean isLightStatus() {
		return lightStatus;
	}
	public void setLightStatus(boolean lightStatus) {
		this.lightStatus = lightStatus;
	}
	/*
	 * These methods all send a message to the server, with a command string
	 * the reply from the server is handled by the receiver, and is not directly connected to these commands.
	 */
	public void isLightOn() 
	{
		if(checkBluetoothSupport())
		{
		new SendData(ServiceCommands.IS_LIGHTS_ON,handler);
		}
	}
	public void setLightsOn() {
		if(checkBluetoothSupport())
		{
		new SendData(ServiceCommands.LIGHTS_ON,handler);
		}
		
	}
	public void setLightsOff() {
		if(checkBluetoothSupport())
		{
		new SendData(ServiceCommands.LIGHTS_OFF,handler);
		}
		
	}
	public void isLocked() {
		if(checkBluetoothSupport())
		{
		new SendData(ServiceCommands.IS_LOCKED,handler);
		}
	}
	public void setLocked() {
		if(checkBluetoothSupport())
		{
		new SendData(ServiceCommands.DOORS_LOCK,handler);
		}
		
	}
	public void setUnlocked() {
		if(checkBluetoothSupport())
		{
		new SendData(ServiceCommands.DOORS_UNLOCK,handler);
		}
	}
	public void closeControllerSession()
	{
		try {
			bluetoothDevice = null;
			bluetoothSocket.close();
			reciever.closeSession();
		} catch (IOException e) {
			Log.e(TAG,e.getMessage());
			e.printStackTrace();
		}
	}
	public void closeRecieveDataSession()
	{
		
		
	}
	public void openNewConnection()
	{
		new ConnectBluetooth().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"Connect");
	}
	
    
    public boolean getOilStatus() {
		return oilStatus;
	}
	public void setOilStatus(boolean oilStatus) {
		this.oilStatus = oilStatus;
	}
	
	
}
